             package com.java.diagnostics.visualizer.gc.i5V5r4.parser;
             
             import com.java.diagnostics.visualizer.data.DataLevel;
             import com.java.diagnostics.visualizer.data.SourceData;
             import com.java.diagnostics.visualizer.data.TupleData;
             import com.java.diagnostics.visualizer.data.TupleDataBuilder;
             import com.java.diagnostics.visualizer.data.axes.AxisPair;
             import com.java.diagnostics.visualizer.data.axes.XDataAxis;
             import com.java.diagnostics.visualizer.data.axes.YDataAxis;
             import com.java.diagnostics.visualizer.exceptions.GCAndMemoryVisualizerException;
             import com.java.diagnostics.visualizer.factory.DataFactory;
             import com.java.diagnostics.visualizer.factory.SourceDataFactory;
             import com.java.diagnostics.visualizer.gc.i5classic.parser.InstanceI5ClassicParser;
             import com.java.diagnostics.visualizer.gc.i5support.util.Messages;
             import com.java.diagnostics.visualizer.impl.factory.LogFactory;
             import com.java.diagnostics.visualizer.metadata.TupleMetaData;
             import com.java.diagnostics.visualizer.metadata.TupleMetaData.TableField;
             import com.java.diagnostics.visualizer.metadata.TupleMetaData.TableType;
             import com.java.diagnostics.visualizer.parser.vgc.VGCPlainTextParser;
             import com.java.diagnostics.visualizer.parser.vgc.constants.VGCAxes;
             import com.java.diagnostics.visualizer.parser.vgc.converters.GCNumberConverter;
             import com.java.diagnostics.visualizer.parsers.Parser;
             import com.java.diagnostics.visualizer.properties.OutputProperties;
             import com.java.diagnostics.visualizer.sources.Source;
             import java.io.BufferedReader;
             import java.io.IOException;
             import java.io.InputStreamReader;
             import java.io.PrintWriter;
             import java.io.StringWriter;
             import java.util.ArrayList;
             import java.util.Calendar;
             import java.util.HashMap;
             import java.util.logging.Level;
             import java.util.logging.Logger;
             import java.util.regex.Matcher;
             import java.util.regex.Pattern;
             
             public class InstanceI5V5r4Parser
               extends VGCPlainTextParser
             {
               private static final Pattern DATE_PATTERN = Pattern.compile("HEAP=([0-9][0-9])/([0-9][0-9])/([0-9][0-9][0-9][0-9]) ([0-9][0-9]):([0-9][0-9]):([0-9][0-9])\\.([0-9][0-9][0-9][0-9][0-9][0-9]) ");
               
               private static final SourceDataFactory SOURCE_DATA_FACTORY = SourceDataFactory.getFactory();
               private final Logger LOGGER = LogFactory.getTrace(Parser.class);
               
               private static final Logger TRACE = LogFactory.getTrace(InstanceI5ClassicParser.class);
               
               private boolean absoluteTime = false;
               private ArrayList chartData;
               private int chartDataIndex = 0;
               private int lowestCycleNumber = 2147483647;
               private int lowestCycleNumberEntry = 0;
               
               private long currentTime;
               
               private String nextLine;
               
               private SourceData sourceData;
               private XDataAxis xAxis;
               private GCNumberConverter gcNumberConverter;
               private YDataAxis heapAxis;
               private YDataAxis numberAxis;
               private YDataAxis timeAxis;
               private TupleDataBuilder softReferences;
               private TupleDataBuilder weakReferences;
               private TupleDataBuilder finalReferences;
               private TupleDataBuilder phantomReferences;
               private TupleDataBuilder cycleTimes;
               private TupleDataBuilder markTimes;
               private TupleDataBuilder sweepTimes;
               private TupleDataBuilder usedHeap;
               private TupleDataBuilder freeHeap;
               private TupleDataBuilder heapSize;
               private TupleDataBuilder freeLOABefore;
               private TupleDataBuilder freeLOAAfter;
               private TupleDataBuilder freeSOABefore;
               private TupleDataBuilder freeSOAAfter;
               private TupleDataBuilder totalLOAAfter;
               private TupleDataBuilder totalSOAAfter;
               private TupleDataBuilder totalLOABefore;
               private TupleDataBuilder totalSOABefore;
               private TupleDataBuilder gcInterval;
               
               protected boolean isTimeStampRelative()
               {
                 return false;
               }
               
               public SourceData parse(Source source, OutputProperties properties) throws GCAndMemoryVisualizerException
               {
                 TRACE.entering(this.className, "parse");
                 
                 createTuples(source, properties);
                 
                 try
                 {
                   String variantIdentifier = source.getVariantIdentifier();
                   this.sourceData = 
                     SOURCE_DATA_FACTORY.createSourceData(variantIdentifier);
                   
                   trace("Ready to open input");
                   BufferedReader reader = new BufferedReader(new InputStreamReader(
                     source.getStream()));
                   
                   this.chartData = new ArrayList(300);
                   
                   String line;
                   do
                   {
                     line = readLine(reader);
                     if (line.trim().startsWith("OPTION ABSOLUTE_TIME")) {
                       this.absoluteTime = true;
                       trace("Absolute time specified");
                     }
                   } while (!
                   
                     line.trim().startsWith("******** BEGIN DUMP"));
                   
                   readStructuredData(reader);
                   
                   long lastTime = 0L;
                   while (reader.ready()) {
                     trace("Ready to read an entry");
                     
                     HashMap entryData = parseEntry(reader, properties);
                     if (entryData == null)
                       break;
                     if (tracing()) {
                       trace("Entry " + this.chartDataIndex + " parsed");
                     }
                     this.chartData.add(entryData);
                     if (entryData.containsKey("Cycle")) {
                       int cycleNum = Integer.parseInt(
                         (String)entryData.get("Cycle"));
                       if (cycleNum < this.lowestCycleNumber) {
                         this.lowestCycleNumber = cycleNum;
                         this.lowestCycleNumberEntry = this.chartDataIndex;
                       }
                     }
                     this.chartDataIndex += 1;
                   }
                   int nextEntry = this.lowestCycleNumberEntry;
                   do {
                     HashMap entryData = (HashMap)this.chartData.get(nextEntry);
                     
                     if (entryData.containsKey("Start_Time")) {
                       this.currentTime = Long.parseLong(
                         (String)entryData.get("Start_Time"));
                     } else {
                       throw new GCAndMemoryVisualizerException(
                         "Could not find Start_Time");
                     }
                     if (lastTime == 0L) {
                       lastTime = this.currentTime;
                     }
                     this.xAxis.setX(this.currentTime);
                     
                     if (entryData.containsKey("Cycle"))
                     {
                       this.gcNumberConverter.addPoint(this.xAxis.getSequenceUID(), 
                         Integer.parseInt((String)entryData.get("Cycle")));
                     }
                     long interval = this.currentTime - lastTime;
                     addDataPoint(this.gcInterval, interval);
                     conditionallyAddNumericPointK(this.freeSOABefore, entryData, 
                       "SOA:Start:Free");
                     conditionallyAddNumericPointK(this.freeSOAAfter, entryData, 
                       "SOA:End:Free");
                     conditionallyAddNumericPointK(this.totalSOABefore, entryData, 
                       "SOA:Start:Total");
                     conditionallyAddNumericPointK(this.totalSOAAfter, entryData, 
                       "SOA:End:Total");
                     conditionallyAddNumericPointK(this.freeLOABefore, entryData, 
                       "LOA:Start:Free");
                     conditionallyAddNumericPointK(this.freeLOAAfter, entryData, 
                       "LOA:End:Free");
                     conditionallyAddNumericPointK(this.totalLOABefore, entryData, 
                       "LOA:Start:Total");
                     conditionallyAddNumericPointK(this.totalLOAAfter, entryData, 
                       "LOA:End:Total");
                     
                     conditionallyAddNumericPoint(this.softReferences, entryData, 
                       "Soft:Cleared");
                     conditionallyAddNumericPoint(this.weakReferences, entryData, 
                       "Weak:Cleared");
                     conditionallyAddNumericPoint(this.finalReferences, entryData, 
                       "Final:Cleared");
                     conditionallyAddNumericPoint(this.phantomReferences, entryData, 
                       "Phantom:Cleared");
                     conditionallyAddNumericPointU(this.cycleTimes, entryData, 
                       "Duration:Heap");
                     conditionallyAddNumericPointU(this.markTimes, entryData, 
                       "Duration:Mark");
                     conditionallyAddNumericPointU(this.sweepTimes, entryData, 
                       "Duration:Sweep");
                     
                     conditionallyAddNumericPointK(this.usedHeap, entryData, 
                       "Tenured:End:Allocated");
                     conditionallyAddNumericPointK(this.freeHeap, entryData, 
                       "Tenured:End:Free");
                     conditionallyAddNumericPointK(this.heapSize, entryData, 
                       "Tenured:Start:Total");
                     lastTime = this.currentTime;
                     if (tracing()) {
                       trace("Entry " + nextEntry + " queued to output");
                     }
                     nextEntry++;
                     if (nextEntry >= this.chartDataIndex) {
                       nextEntry = 0;
                     }
                   } while (nextEntry != this.lowestCycleNumberEntry);
                   
                   this.sourceData.addData(this.gcInterval, DataLevel.VARIANT);
                   this.sourceData.addData(this.freeSOABefore, DataLevel.VARIANT);
                   this.sourceData.addData(this.freeSOAAfter, DataLevel.VARIANT);
                   this.sourceData.addData(this.totalSOABefore, DataLevel.VARIANT);
                   this.sourceData.addData(this.totalSOAAfter, DataLevel.VARIANT);
                   this.sourceData.addData(this.freeLOABefore, DataLevel.VARIANT);
                   this.sourceData.addData(this.freeLOAAfter, DataLevel.VARIANT);
                   this.sourceData.addData(this.totalLOABefore, DataLevel.VARIANT);
                   this.sourceData.addData(this.totalLOAAfter, DataLevel.VARIANT);
                   this.sourceData.addData(this.softReferences, DataLevel.VARIANT);
                   this.sourceData.addData(this.weakReferences, DataLevel.VARIANT);
                   this.sourceData.addData(this.finalReferences, DataLevel.VARIANT);
                   this.sourceData.addData(this.phantomReferences, DataLevel.VARIANT);
                   this.sourceData.addData(this.cycleTimes, DataLevel.VARIANT);
                   this.sourceData.addData(this.markTimes, DataLevel.VARIANT);
                   this.sourceData.addData(this.sweepTimes, DataLevel.VARIANT);
                   
                   this.sourceData.addData(this.freeHeap, DataLevel.VARIANT);
                   this.sourceData.addData(this.heapSize, DataLevel.VARIANT);
                   
                   if (!this.absoluteTime) {
                     this.xAxis.updateNormalisation(this.sourceData);
                   }
                 } catch (GCAndMemoryVisualizerException ex) {
                   throw ex;
                 } catch (IOException ex) {
                   this.LOGGER.log(Level.SEVERE, " -- IOException while parsing source: ", 
                     ex);
                   throw new GCAndMemoryVisualizerException(ex);
                 } catch (Throwable ex) {
                   this.LOGGER.log(Level.SEVERE, " -- Exception while parsing source: ", 
                     ex);
                   StringWriter stringWriter = new StringWriter();
                   PrintWriter printWriter = new PrintWriter(stringWriter);
                   ex.printStackTrace(printWriter);
                   throw new GCAndMemoryVisualizerException("Caught:\n" + 
                     stringWriter.toString());
                 }
                 TRACE.exiting(this.className, "parse");
                 return this.sourceData;
               }
               
               private void readStructuredData(BufferedReader reader) throws IOException {
                 String line;
                 do {
                   line = readLine(reader);
                 } while (!
                 
                   line.trim().equals("GC CYCLE TABLE:"));
               }
               
               private HashMap parseEntry(BufferedReader reader, OutputProperties properties) throws IOException
               {
                 HashMap result = new HashMap();
                 
                 String line = readLine(reader).trim();
                 if (line.trim().startsWith("******** END DUMP")) {
                   return null;
                 }
                 int[] cursor = new int[1];
                 cursor[0] = 0;
                 String value = nextValue(line, cursor);
                 result.put("Cycle", value);
                 value = nextValue(line, cursor);
                 result.put("Reason", value);
                 value = nextValue(line, cursor);
                 result.put("Type", value);
                 value = nextValue(line, cursor);
                 result.put("Internal_Cycles", value);
                 value = nextValue(line, cursor);
                 result.put("Excessive_GC", value);
                 value = nextValue(line, cursor);
                 result.put("Interval_Time", value);
                 
                 readLine(reader);
                 
                 line = readLine(reader).trim();
                 long longValue = getTime(line);
                 result.put("Start_Time", Long.toString(longValue));
                 value = lastValue(line);
                 result.put("Duration:Heap", value);
                 line = readLine(reader).trim();
                 value = lastValue(line);
                 result.put("Duration:Mark", value);
                 line = readLine(reader).trim();
                 value = lastValue(line);
                 result.put("Duration:Sweep", value);
                 
                 line = readLine(reader).trim();
                 if (line.startsWith("COMPACT="))
                 {
                   readLine(reader);
                 }
                 
                 line = readLine(reader).trim();
                 cursor[0] = 0;
                 
                 value = nextValue(line, cursor);
                 
                 String[] values = decompose(value);
                 result.put("GC_Heap:Start:Total", values[0]);
                 result.put("GC_Heap:Start:Allocated", values[1]);
                 result.put("GC_Heap:Start:Free", values[2]);
                 
                 value = nextValue(line, cursor);
                 
                 values = decompose(value);
                 result.put("GC_Heap:End:Total", values[0]);
                 result.put("GC_Heap:End:Allocated", values[1]);
                 result.put("GC_Heap:End:Free", values[2]);
                 
                 line = readLine(reader).trim();
                 cursor[0] = 0;
                 
                 value = nextValue(line, cursor);
                 
                 values = decompose(value);
                 result.put("Nursery:Start:Total", values[0]);
                 result.put("Nursery:Start:Allocated", values[1]);
                 result.put("Nursery:Start:Free", values[2]);
                 
                 value = nextValue(line, cursor);
                 
                 values = decompose(value);
                 result.put("Nursery:End:Total", values[0]);
                 result.put("Nursery:End:Allocated", values[1]);
                 result.put("Nursery:End:Free", values[2]);
                 
                 value = nextValue(line, cursor);
                 
                 values = decompose(value);
                 result.put("Tenured:Start:Total", values[0]);
                 result.put("Tenured:Start:Allocated", values[1]);
                 result.put("Tenured:Start:Free", values[2]);
                 
                 value = nextValue(line, cursor);
                 
                 values = decompose(value);
                 result.put("Tenured:End:Total", values[0]);
                 result.put("Tenured:End:Allocated", values[1]);
                 result.put("Tenured:End:Free", values[2]);
                 
                 line = readLine(reader).trim();
                 cursor[0] = 0;
                 
                 value = nextValue(line, cursor);
                 
                 values = decompose(value);
                 result.put("SOA:Start:Total", values[0]);
                 result.put("SOA:Start:Allocated", values[1]);
                 result.put("SOA:Start:Free", values[2]);
                 
                 value = nextValue(line, cursor);
                 
                 values = decompose(value);
                 result.put("SOA:End:Total", values[0]);
                 result.put("SOA:End:Allocated", values[1]);
                 result.put("SOA:End:Free", values[2]);
                 
                 value = nextValue(line, cursor);
                 
                 values = decompose(value);
                 result.put("LOA:Start:Total", values[0]);
                 result.put("LOA:Start:Allocated", values[1]);
                 result.put("LOA:Start:Free", values[2]);
                 
                 value = nextValue(line, cursor);
                 
                 values = decompose(value);
                 result.put("LOA:End:Total", values[0]);
                 result.put("LOA:End:Allocated", values[1]);
                 result.put("LOA:End:Free", values[2]);
                 
                 line = readLine(reader).trim();
                 cursor[0] = 0;
                 
                 nextValue(line, cursor);
                 
                 value = nextValue(line, cursor);
                 
                 values = decompose(value);
                 result.put("Final:Start", values[0]);
                 result.put("Final:End", values[1]);
                 long freed = Long.parseLong(values[0]) - Long.parseLong(values[1]);
                 result.put("Final:Cleared", Long.toString(freed));
                 
                 value = nextValue(line, cursor);
                 
                 values = decompose(value);
                 result.put("Weak:Start", values[0]);
                 result.put("Weak:End", values[1]);
                 freed = Long.parseLong(values[0]) - Long.parseLong(values[1]);
                 result.put("Weak:Cleared", Long.toString(freed));
                 
                 value = nextValue(line, cursor);
                 
                 values = decompose(value);
                 result.put("Soft:Start", values[0]);
                 result.put("Soft:End", values[1]);
                 freed = Long.parseLong(values[0]) - Long.parseLong(values[1]);
                 result.put("Soft:Cleared", Long.toString(freed));
                 
                 value = nextValue(line, cursor);
                 
                 values = decompose(value);
                 result.put("Phantom:Start", values[0]);
                 result.put("Phantom:End", values[1]);
                 freed = Long.parseLong(values[0]) - Long.parseLong(values[1]);
                 result.put("Phantom:Cleared", Long.toString(freed));
                 
                 return result;
               }
               
               private String readLine(BufferedReader reader) throws IOException {
                 if (this.nextLine == null) {
                   this.nextLine = readRawLine(reader);
                 }
                 String line = this.nextLine;
                 this.nextLine = readRawLine(reader);
                 if (line.trim().endsWith("+")) {
                   line = line.substring(0, line.lastIndexOf('+'));
                   line = line + this.nextLine;
                   this.nextLine = readRawLine(reader);
                 }
                 return line.trim().toUpperCase();
               }
               
               private String readRawLine(BufferedReader reader) throws IOException {
                 String line;
                 do {
                   line = reader.readLine();
                 } while ((line != null) && (
                   line.trim().startsWith("DISPLAY/ALTER/DUMP")));
                 return line;
               }
               
               private String nextValue(String line, int[] cursor)
               {
                 int position = line.indexOf('=', cursor[0]);
                 if (position == -1)
                   return null;
                 int space = line.indexOf(' ', position);
                 if (space == -1)
                   space = line.length();
                 String value = line.substring(position + 1, space);
                 cursor[0] = (space + 1);
                 return value;
               }
               
               private String lastValue(String line)
               {
                 int position = line.lastIndexOf(' ');
                 if (position == -1)
                   return null;
                 return line.substring(position + 1);
               }
               
               private String[] decompose(String value)
               {
                 if (value == null)
                   return null;
                 String[] result = new String[4];
                 int position = 0;
                 int index = 0;
                 while (position < value.length()) {
                   int slash = value.indexOf('/', position);
                   if (slash == -1)
                     slash = value.length();
                   result[(index++)] = value.substring(position, slash);
                   position = slash + 1;
                 }
                 return result;
               }
               
               private long getTime(String line) {
                 Matcher matcher = DATE_PATTERN.matcher(line);
                 matcher.find();
                 int month = Integer.parseInt(matcher.group(1));
                 int day = Integer.parseInt(matcher.group(2));
                 int year = Integer.parseInt(matcher.group(3));
                 int hour = Integer.parseInt(matcher.group(4));
                 int minute = Integer.parseInt(matcher.group(5));
                 int second = Integer.parseInt(matcher.group(6));
                 long us = Integer.parseInt(matcher.group(7));
                 
                 Calendar cal = Calendar.getInstance();
                 cal.set(year + 2000, month, day, hour, 0, 0);
                 
                 long msFlaky = cal.getTimeInMillis();
                 
                 long hours = (msFlaky + 1800000L) / 3600000L;
                 
                 us = ((hours * 60L + minute) * 60L + second) * 1000L * 1000L + us;
                 return (us + 500L) / 1000L;
               }
               
               private void conditionallyAddNumericPoint(TupleData tupleData, HashMap entryData, String id)
               {
                 if (entryData.containsKey(id)) {
                   addNumericPoint(tupleData, entryData.get(id));
                 } else {
                   this.LOGGER.log(Level.SEVERE, "ID not found:" + id);
                 }
               }
               
               private void addNumericPoint(TupleData tupleData, Object value) {
                 addDataPoint(tupleData, Long.parseLong((String)value));
               }
               
               private void conditionallyAddNumericPointK(TupleData tupleData, HashMap entryData, String id)
               {
                 if (entryData.containsKey(id)) {
                   addNumericPointK(tupleData, entryData.get(id));
                 } else {
                   this.LOGGER.log(Level.SEVERE, "ID not found:" + id);
                 }
               }
               
               private void addNumericPointK(TupleData tupleData, Object value) {
                 addDataPoint(tupleData, Long.parseLong((String)value) * 1024L);
               }
               
               private void conditionallyAddNumericPointU(TupleData tupleData, HashMap entryData, String id)
               {
                 if (entryData.containsKey(id)) {
                   addNumericPointU(tupleData, entryData.get(id));
                 } else {
                   this.LOGGER.log(Level.SEVERE, "ID not found:" + id);
                 }
               }
               
               private void addNumericPointU(TupleData tupleData, Object value)
               {
                 addDataPoint(tupleData, (Long.parseLong((String)value) + 500L) / 1000L);
               }
               
               private void addDataPoint(TupleData tupleData, long value) {
                 tupleData.addDataPoint(value, "");
               }
               
               private void createTuples(Source source, OutputProperties properties)
                 throws GCAndMemoryVisualizerException
               {
                 this.gcNumberConverter = new GCNumberConverter();
                 this.xAxis = VGCAxes.prepareXAxis(source, this.gcNumberConverter, properties);
                 
                 this.heapAxis = VGCAxes.prepareHeapAxis(properties);
                 this.numberAxis = VGCAxes.prepareNumberAxis(properties);
                 this.timeAxis = VGCAxes.prepareTimeAxis(properties);
                 
                 this.cycleTimes = 
                   createPauseTuple("I5V5r4Labels.total.cycle.times", this.xAxis, this.timeAxis);
                 
                 this.markTimes = createPauseTuple("VGCLabels.mark.times", this.xAxis, this.timeAxis);
                 
                 this.sweepTimes = createPauseTuple("VGCLabels.sweep.times", this.xAxis, this.timeAxis);
                 
                 this.softReferences = 
                   createTuple("VGCLabels.soft.references.cleared", this.xAxis, this.numberAxis);
                 
                 this.weakReferences = 
                   createTuple("VGCLabels.weak.references.cleared", this.xAxis, this.numberAxis);
                 
                 this.finalReferences = 
                   createTuple("VGCLabels.objects.queued.for.finalization", this.xAxis, this.numberAxis);
                 
                 this.phantomReferences = 
                   createTuple("VGCLabels.phantom.references.cleared", this.xAxis, this.numberAxis);
                 
                 this.usedHeap = 
                   createHeapTuple("VGCLabels.live.normal.heap.after.gc", this.xAxis, this.heapAxis);
                 
                 this.freeHeap = 
                   createHeapTuple("VGCLabels.free.flat.heap", this.xAxis, this.heapAxis);
                 
                 this.heapSize = createHeapTuple("VGCLabels.flat.heap.size", this.xAxis, this.heapAxis);
                 
                 this.freeLOABefore = 
                   createHeapTuple("VGCLabels.free.loa.before.collection", this.xAxis, this.heapAxis);
                 
                 this.freeLOAAfter = 
                   createHeapTuple("VGCLabels.free.loa.after.collection", this.xAxis, this.heapAxis);
                 
                 this.freeSOABefore = 
                   createHeapTuple("VGCLabels.free.soa.before.collection", this.xAxis, this.heapAxis);
                 
                 this.freeSOAAfter = 
                   createHeapTuple("VGCLabels.free.soa.after.collection", this.xAxis, this.heapAxis);
                 
                 this.totalLOABefore = 
                   createHeapTuple("VGCLabels.total.loa.before", this.xAxis, this.heapAxis);
                 
                 this.totalLOAAfter = 
                   createHeapTuple("VGCLabels.total.loa.after", this.xAxis, this.heapAxis);
                 
                 this.totalSOABefore = 
                   createHeapTuple("VGCLabels.total.soa.before", this.xAxis, this.heapAxis);
                 
                 this.totalSOAAfter = 
                   createHeapTuple("VGCLabels.total.soa.after", this.xAxis, this.heapAxis);
                 
                 this.gcInterval = createTuple("VGCLabels.trigger.intervals", this.xAxis, this.timeAxis);
                 
                 TupleMetaData softReferencesMetaData = new TupleMetaData(
                   TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] {
                   TupleMetaData.TableField.MEAN, TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX, TupleMetaData.TableField.TOTAL });
                 TupleMetaData weakReferencesMetaData = new TupleMetaData(
                   TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] { TupleMetaData.TableField.MEAN, 
                   TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX, TupleMetaData.TableField.TOTAL });
                 TupleMetaData finalReferencesMetaData = new TupleMetaData(
                   TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] { TupleMetaData.TableField.MEAN, 
                   TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX, TupleMetaData.TableField.TOTAL });
                 TupleMetaData phantomReferencesMetaData = new TupleMetaData(
                   TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] { TupleMetaData.TableField.MEAN, 
                   TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX, TupleMetaData.TableField.TOTAL });
                 TupleMetaData markTimesMetaData = new TupleMetaData(
                   TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] { TupleMetaData.TableField.MEAN, 
                   TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX, TupleMetaData.TableField.TOTAL });
                 TupleMetaData sweepTimesMetaData = new TupleMetaData(
                   TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] { TupleMetaData.TableField.MEAN, 
                   TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX, TupleMetaData.TableField.TOTAL });
                 TupleMetaData usedHeapMetaData = new TupleMetaData(
                   TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] { TupleMetaData.TableField.MEAN, 
                   TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX });
                 TupleMetaData freeHeapMetaData = new TupleMetaData(
                   TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] { TupleMetaData.TableField.MEAN, 
                   TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX });
                 TupleMetaData heapSizeMetaData = new TupleMetaData(
                   TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] { TupleMetaData.TableField.MEAN, 
                   TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX });
                 TupleMetaData freeLOABeforeMetaData = new TupleMetaData(
                   TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] { TupleMetaData.TableField.MEAN, 
                   TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX });
                 TupleMetaData freeLOAAfterMetaData = new TupleMetaData(
                   TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] { TupleMetaData.TableField.MEAN, 
                   TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX });
                 TupleMetaData freeSOABeforeMetaData = new TupleMetaData(
                   TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] { TupleMetaData.TableField.MEAN, 
                   TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX });
                 TupleMetaData freeSOAAfterMetaData = new TupleMetaData(
                   TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] { TupleMetaData.TableField.MEAN, 
                   TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX });
                 TupleMetaData totalLOABeforeMetaData = new TupleMetaData(
                   TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] { TupleMetaData.TableField.MEAN, 
                   TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX });
                 TupleMetaData totalSOABeforeMetaData = new TupleMetaData(
                   TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] { TupleMetaData.TableField.MEAN, 
                   TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX });
                 TupleMetaData totalLOAAfterMetaData = new TupleMetaData(
                   TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] { TupleMetaData.TableField.MEAN, 
                   TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX });
                 TupleMetaData totalSOAAfterMetaData = new TupleMetaData(
                   TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] { TupleMetaData.TableField.MEAN, 
                   TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX });
                 TupleMetaData gcIntervalMetaData = new TupleMetaData(
                   TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] { TupleMetaData.TableField.MEAN, 
                   TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX });
                 TupleMetaData cycleTimesMetaData = new TupleMetaData(
                   TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] { TupleMetaData.TableField.MEAN, 
                   TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX });
                 
                 this.softReferences.setTupleMetaData(softReferencesMetaData);
                 this.weakReferences.setTupleMetaData(weakReferencesMetaData);
                 this.finalReferences.setTupleMetaData(finalReferencesMetaData);
                 this.phantomReferences.setTupleMetaData(phantomReferencesMetaData);
                 this.markTimes.setTupleMetaData(markTimesMetaData);
                 this.sweepTimes.setTupleMetaData(sweepTimesMetaData);
                 this.usedHeap.setTupleMetaData(usedHeapMetaData);
                 this.freeHeap.setTupleMetaData(freeHeapMetaData);
                 this.heapSize.setTupleMetaData(heapSizeMetaData);
                 this.freeLOABefore.setTupleMetaData(freeLOABeforeMetaData);
                 this.freeLOAAfter.setTupleMetaData(freeLOAAfterMetaData);
                 this.freeSOABefore.setTupleMetaData(freeSOABeforeMetaData);
                 this.freeSOAAfter.setTupleMetaData(freeSOAAfterMetaData);
                 this.totalLOABefore.setTupleMetaData(totalLOABeforeMetaData);
                 this.totalSOABefore.setTupleMetaData(totalSOABeforeMetaData);
                 this.totalLOAAfter.setTupleMetaData(totalLOAAfterMetaData);
                 this.totalSOAAfter.setTupleMetaData(totalSOAAfterMetaData);
                 this.gcInterval.setTupleMetaData(gcIntervalMetaData);
                 this.cycleTimes.setTupleMetaData(cycleTimesMetaData);
               }
               
               private TupleDataBuilder createTuple(String label, XDataAxis xAxis, YDataAxis yAxis)
               {
                 AxisPair axisPair = factory.createAxisPair(xAxis, yAxis);
                 return factory.createTupleData(label, Messages.getString(label), 
                   axisPair);
               }
               
               private TupleDataBuilder createHeapTuple(String label, XDataAxis xAxis, YDataAxis yAxis)
               {
                 AxisPair axisPair = heapFactory.createAxisPair(xAxis, yAxis);
                 return heapFactory.createTupleData(label, Messages.getString(label), 
                   axisPair);
               }
               
               private TupleDataBuilder createPauseTuple(String label, XDataAxis xAxis, YDataAxis yAxis)
               {
                 AxisPair axisPair = pauseFactory.createAxisPair(xAxis, yAxis);
                 return pauseFactory.createTupleData(label, Messages.getString(label), 
                   axisPair);
               }
               
               private boolean tracing() {
                 return this.LOGGER.isLoggable(Level.FINE);
               }
               
               private void trace(String message) {
                 this.LOGGER.log(Level.FINE, message);
               }
             }

